package com.sxkiler.demo.rpc.client;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.sxkiler.demo.rpc.model.MessageContext;
import com.sxkiler.demo.rpc.model.Request;
import com.sxkiler.demo.rpc.model.Response;
import com.sxkiler.demo.rpc.nacos.NacosTemplate;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class RpcClientProxy implements RpcClientFactory{
    private static Logger logger = LoggerFactory.getLogger(RpcClientProxy.class);
    private static Map<Class,RpcClient> rpcClientCache = new HashMap<>();

    /**
     * 这里需要考虑如果下游重启了，这个rpclient是否还有效
     * @param serviceClass
     * @return
     * @throws Exception
     */
    public static RpcClient getRpcClient(Class serviceClass) throws Exception {
        //集成nacos用，这里可以去掉。从nacos中负载均衡获取一个健康的服务实例
        Instance nettyServices = NacosTemplate.getOneHealthyInstance(serviceClass.getSimpleName());
        RpcClient client = new RpcClient(nettyServices.getIp(),nettyServices.getPort());
        return client;
    }

    /**
     * 首先通过nacosTemplate获取到对象的ip和端口,同时构建rpcClient
     * @param className
     * @param <T>
     * @return
     */
    public  <T> T getBean(Class<T> className) {
        //通过proxy创建被调用者className的代理对象。
        Enhancer enhancer = new Enhancer();
        enhancer.setUseCache(true);
        enhancer.setSuperclass(className);
        enhancer.setCallback(new SerivceMethodInterceptor(className.getSimpleName(),className));
        return (T)enhancer.create();
    }

    private static class SerivceMethodInterceptor implements MethodInterceptor {
        private String beanName;
        private Class<?> classType;

        private SerivceMethodInterceptor(String beanName, Class<?> classType) {
            this.classType = classType;
            this.beanName = beanName;
        }

        @Override
        public Object intercept(Object serviceObject, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            if("toString".equals(method.getName())){
                return new Object();
            }
            Request request = new Request();
            request.setReqId(RandomUtil.randomString(32));
            request.setClassName(classType.getName());
            request.setMethodName(method.getName());
            request.setParameterType(method.getParameterTypes());
            request.setParameterValue(objects);
            request.setServiceNameByAnnotated(classType.getSimpleName());
            System.out.println(request);


            //把消息体放入到nettyClientHandler中，以供nettyClientHandler去发送数据
            RpcClient client = getRpcClient(classType);
            if (client.getRpcClientHandler() != null) {
                RpcClientHandler clientHandler = client.getRpcClientHandler();
                MessageContext resContext =  clientHandler.sendRequest(request);
                Response response = JSON.parseObject(JSONObject.toJSONString(resContext.getContext()), Response.class);
                return JSON.parseObject(JSONObject.toJSONString(response.getContext()), response.getContextType());
            }
            return null;
        }
    }

}
